package edison.jcr.security;

import javax.jcr.AccessDeniedException;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.lock.LockException;
import javax.jcr.security.AccessControlException;
import javax.jcr.security.AccessControlManager;
import javax.jcr.security.AccessControlPolicy;
import javax.jcr.security.AccessControlPolicyIterator;
import javax.jcr.security.Privilege;
import javax.jcr.version.VersionException;

import edison.persistence.ItemService;
import edison.persistence.PersistenceException;
import edison.persistence.SecurityService;

public class AccessControlManagerImpl implements AccessControlManager {

	private SecurityService securityService;
	private ItemService itemService;
	private final Session session;

	public AccessControlManagerImpl(Session session) {
		super();
		this.session = session;
	}

	public Privilege[] getSupportedPrivileges(String absPath) throws PathNotFoundException, RepositoryException {
		String[] privilegeNames;
		try {
			if (!itemService.itemExists(absPath))
				throw new PathNotFoundException();

			privilegeNames = securityService.getSupportedPrivilegesByPath(absPath);
		} catch (PersistenceException e) {
			throw new RepositoryException(e);
		}

		Privilege[] privileges = build(privilegeNames);
		return privileges;
	}

	private Privilege[] build(String[] privilegeNames) {
		Privilege[] privileges = new PrivilegeImpl[privilegeNames.length];
		for (int i = 0; i < privileges.length; i++) {
			privileges[i] = PrivilegeImpl.MAP.get(privilegeNames[i]);
		}
		return privileges;
	}

	public Privilege privilegeFromName(String privilegeName) throws AccessControlException, RepositoryException {

		if (PrivilegeImpl.MAP.containsKey(privilegeName)) {
			return PrivilegeImpl.MAP.get(privilegeName);
		}

		throw new AccessControlException();

	}

	public boolean hasPrivileges(String absPath, Privilege[] privileges) throws PathNotFoundException, RepositoryException {

		try {
			if (!itemService.itemExists(absPath)) {
				throw new PathNotFoundException();
			}

			String[] privilegeNames = getNames(privileges);
			return securityService.hasPrivileges(session.getUserID(), absPath, privilegeNames);
		} catch (PersistenceException e) {
			throw new RepositoryException(e);
		}
	}

	private String[] getNames(Privilege[] privileges) {
		String[] privilegeNames = new String[privileges.length];
		for (int i = 0; i < privilegeNames.length; i++) {
			privilegeNames[i] = privileges[i].getName();
		}
		return privilegeNames;
	}

	public Privilege[] getPrivileges(String absPath) throws PathNotFoundException, RepositoryException {
		String[] privilegeNames;
		try {
			if (!itemService.itemExists(absPath))
				throw new PathNotFoundException();

			privilegeNames = securityService.getPrivilegesByPath(session.getUserID(), absPath);
		} catch (PersistenceException e) {
			throw new RepositoryException(e);
		}

		Privilege[] privileges = build(privilegeNames);
		return privileges;
	}

	public AccessControlPolicy[] getPolicies(String absPath) throws PathNotFoundException, AccessDeniedException, RepositoryException {
		try {
			if (!itemService.itemExists(absPath))
				throw new PathNotFoundException();

			if (!securityService.hasPrivileges(session.getUserID(), absPath, new String[] { Privilege.JCR_READ_ACCESS_CONTROL }))
				throw new AccessDeniedException("lacks READ_ACCESS_CONTROL privilege");

		} catch (PersistenceException e) {
			throw new RepositoryException(e);
		}
		return null;
	}

	public AccessControlPolicy[] getEffectivePolicies(String absPath) throws PathNotFoundException, AccessDeniedException, RepositoryException {
		try {
			if (!itemService.itemExists(absPath))
				throw new PathNotFoundException();

			if (!securityService.hasPrivileges(session.getUserID(), absPath, new String[] { Privilege.JCR_READ_ACCESS_CONTROL }))
				throw new AccessDeniedException("lacks READ_ACCESS_CONTROL privilege");

			securityService.getNamedAccessControlPolicies(session.getUserID(), absPath);
			securityService.getAccessControlList(session.getUserID(), absPath);
		} catch (PersistenceException e) {
			throw new RepositoryException(e);
		}
		return null;
	}

	public AccessControlPolicyIterator getApplicablePolicies(String absPath) throws PathNotFoundException, AccessDeniedException, RepositoryException {
		// TODO Auto-generated method stub
		return null;
	}

	public void setPolicy(String absPath, AccessControlPolicy policy) throws PathNotFoundException, AccessControlException, AccessDeniedException, LockException, VersionException, RepositoryException {
		// TODO Auto-generated method stub

	}

	public void removePolicy(String absPath, AccessControlPolicy policy) throws PathNotFoundException, AccessControlException, AccessDeniedException, LockException, VersionException, RepositoryException {
		// TODO Auto-generated method stub

	}
}